/* $RCSFile: MetaDataCache.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/CRMWrapper3/MetaDataCache.cs $
 * $log$
 * Revision 6 2010/08/06 19:56:32  christian.surieux
 *   Added Log to All cs files
 */

// =======================================================================
//  File: MetaDataCache.cs
// =======================================================================
//  This file is part of Addon Nice product.
//  Copyright (C) Addon Nice.  All rights reserved.
// =======================================================================

using System;
using System.Diagnostics;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Resources;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;

using CrmSdk;
using AddonNice.Settings;
using AddonNice.CRMWrapper.Design;

namespace AddonNice.CRMWrapper
{
	/// <summary>
	/// This metadata cache is used to cache entity metadata that is commonly used throughout the application
	/// </summary>
	public class MetadataCache
	{
		// Unique Key used to inserts objects into the cache
		private const string CACHE_KEY = "ADNCRMWrapperMetadataKey";

		private MetadataCache() { }

		static MetadataCache() { }

        /// <summary>
        /// remove all current cache key 
        /// </summary>
        public static void Reset()
        {
            Settings.Cache.CurrentCache.RemoveAll(CACHE_KEY);
        }


		/// <summary>
		/// Retrieves an entity that is cached
		/// </summary>
		/// <param name="entityName">Schema name of the entity</param>
		/// <returns>EntityMetadata of the entity</returns>
		public static EntityInternalMetadata GetEntityMetadata(CRMWrapperBase wrapper, string entityName,EntityInternalItems f, bool isAdmin)
		{
            object[] ob1            =   new object[]{CACHE_KEY,entityName,f,isAdmin,wrapper.CrmServiceUrl,wrapper.OrganizationName,wrapper.CrmVersion};
			if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MetadataCache GetEntityMetadata BEG CACHE_KEY: {0}, entityName: {1}, f: {2}, isAdmin: {3}, CrmServiceUrl: {4}, OrganizationName: {5}, CrmVersion: {6}.",
                    ob1),CRMTraceSwitch.Sw.Info);
			string metadataKey			=   string.Format("{0}_{1}_{2}_{3}_{4}_{5}_{6}",ob1).Replace(' ','_').Replace(',','_');

			// Retrieve entity metadata from cache
            object[] ob                 =    (object[])Settings.Cache.CurrentCache.Get(metadataKey);
            EntityInternalMetadata entity		= null;
			// If the entity metadata was found, return it
			if ( ob != null && !wrapper.MetadataHasChanged((string)ob[1]) )
			{
				if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MetadataCache GetEntityMetadata cache match entity: {0}, key: {1}.",entityName,metadataKey),CRMTraceSwitch.Sw.Info);
                return (EntityInternalMetadata)ob[0];
			}

			// Retrieve entity metadata with all flags			
			entity						=   wrapper.internalRetrieveEntityMetadata(entityName, f, isAdmin);
            string timestamp            =   wrapper.LastTimestamp;
			if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MetadataCache GetEntityMetadata insert in cache entity: {0}, key: {1}, timestamp: {2}.",entityName,metadataKey,timestamp),CRMTraceSwitch.Sw.Info);
			// Insert the entity metadata into the cache 15 minutes
            ob                          =   new object[]{entity,timestamp};
			Settings.Cache.CurrentCache.InsertMinutes(metadataKey,ob, Config.CRMMetadataCacheTime);
			if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]MetadataCache GetEntityMetadata END.",CRMTraceSwitch.Sw.Info);
			return entity;
		}

        /// <summary>
        /// This adds all entities in the system (supported and custom), or get it from cache after checking crm timestamp
        /// Returns true when found in cache 
        /// </summary>
        public static bool BuildEntitiesList(CRMWrapperBase wrapper,EntityInternalItems f,bool isAdmin,bool customOnly,ref SortedList<string,EntityConfig> Lst,EntityNameDelegate fn)
        {
			if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MetadataCache BuildEntitiesList BEG isAdmin: {0}, customOnly: {1}, EntityInternalItems: {2}.",isAdmin,customOnly,f),CRMTraceSwitch.Sw.Info);
			string metadataKey			=   string.Format("{0}2_{1}_{2}_{3}_{4}_{5}_{6}",
                new object[]{CACHE_KEY,f,isAdmin,customOnly,wrapper.CrmServiceUrl,wrapper.OrganizationName,wrapper.CrmVersion}).Replace(' ','_').Replace(',','_');

			// Retrieve entity metadata from cache
            object[] ob                 =   (object[])Settings.Cache.CurrentCache.Get(metadataKey);
			// If the entity metadata was found, return it
			if ( ob != null && !wrapper.MetadataHasChanged((string)ob[1]) )
			{
				if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MetadataCache BuildEntitiesList cache match key: {0}.",metadataKey),CRMTraceSwitch.Sw.Info);
                Lst                     =   (SortedList<string,EntityConfig>)ob[0];
                return true;
			}
            wrapper.IterateMetaEntities(f,isAdmin,customOnly,fn);
            string timestamp            =   wrapper.LastTimestamp;
			if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MetadataCache BuildEntitiesList END insert in cache key: {0}, timestamp: {1}.",metadataKey,timestamp),CRMTraceSwitch.Sw.Info);
			// Insert the entity metadata into the cache 15 minutes
            ob                          =   new object[]{Lst,timestamp};
			Settings.Cache.CurrentCache.InsertMinutes(metadataKey,ob, Config.CRMMetadataCacheTime);
			if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MetadataCache BuildEntitiesList END Count: {0}.",Lst.Count),CRMTraceSwitch.Sw.Info);
            return false;
        }
        
        /// <summary>
        /// Build an array list with all entities or get it from cache after checking crm timestamp
        /// useAll true means take all entities, false for using a specific subset of classical entities
        /// </summary>
        public static ArrayList GetAllEntities(CRMWrapperBase Wrapper,bool useAll)
        {
            object[] ob1                        =   new object[]{CACHE_KEY,useAll,Wrapper.CrmServiceUrl,Wrapper.OrganizationName,Wrapper.CrmVersion};
			if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MetadataCache GetAllEntities BEG CACHE_KEY: {0}, useAll: {1}, CrmServiceUrl: {2}, OrganizationName: {3}, CrmVersion: {4}",ob1),CRMTraceSwitch.Sw.Info);
			string metadataKey			        =   string.Format("{0}3_{1}_{2}_{3}_{4}",
                ob1).Replace(' ','_').Replace(',','_');

			// Retrieve entity metadata from cache
            object[] ob                         =   (object[])Settings.Cache.CurrentCache.Get(metadataKey);
			// If the entity metadata was found, return it
			if ( ob != null && !Wrapper.MetadataHasChanged((string)ob[1]) )
			{
				if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MetadataCache GetAllEntities cache match key: {0}.",metadataKey),CRMTraceSwitch.Sw.Info);
                return (ArrayList)ob[0];
			}
            ArrayList AllEntities               =   new ArrayList();
            if (useAll)
            {
                Wrapper.IterateMetaEntities(
                    EntityInternalItems.EntityOnly, true, false,
                    delegate(string entityNm, string displayNm)
                    {
                        int typeCd              =   Wrapper.GetObjectTypeCode(entityNm);
                        CrmEntityListItem it    =   new CrmEntityListItem(displayNm, typeCd, entityNm);
                        AllEntities.Add(it);
                    }
                    );
            }
            else
            {
                List<string> lst                =   Wrapper.GetEntityList();
                foreach (string ent in lst)
                {
                    int typeCd                  =   Wrapper.GetObjectTypeCode(ent);
                    string displayNm            =   Wrapper.GetDisplayName(ent);
                    CrmEntityListItem it        =   new CrmEntityListItem(displayNm, typeCd, ent);
                    AllEntities.Add(it);
                }
            }
            string timestamp                    =   Wrapper.LastTimestamp;
			if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MetadataCache GetAllEntities END insert in cache Count: {0}, timestamp: {1}.",AllEntities.Count,timestamp),CRMTraceSwitch.Sw.Info);
			// Insert the entity metadata into the cache 15 minutes
            ob                                  =   new object[]{AllEntities,timestamp};
			Settings.Cache.CurrentCache.InsertMinutes(metadataKey,ob, Config.CRMMetadataCacheTime);
            return AllEntities;
        }
        
        /// <summary>
        /// Build a Sorted list with all custom entities or get it from cache after checking crm timestamp
        /// </summary>
        public static SortedList<string,CrmEntityListItem> GetCustomEntities(CRMWrapperBase Wrapper)
        {
            object[] ob1                        =   new object[]{CACHE_KEY,Wrapper.CrmServiceUrl,Wrapper.OrganizationName,Wrapper.CrmVersion};
			if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MetadataCache GetCustomEntities BEG CACHE_KEY: {0}, CrmServiceUrl: {1}, OrganizationName: {2}, CrmVersion: {3}",ob1),CRMTraceSwitch.Sw.Info);
			string metadataKey			        =   string.Format("{0}4_{1}_{2}_{3}",
                ob1).Replace(' ','_').Replace(',','_');

			// Retrieve entity metadata from cache
            object[] ob                         =   (object[])Settings.Cache.CurrentCache.Get(metadataKey);
			// If the entity metadata was found, return it
			if ( ob != null && !Wrapper.MetadataHasChanged((string)ob[1]) )
			{
				if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MetadataCache GetCustomEntities cache match key: {0}.",metadataKey),CRMTraceSwitch.Sw.Info);
                return (SortedList<string,CrmEntityListItem>)ob[0];
			}
            SortedList<string,CrmEntityListItem> AllEntities   =   new SortedList<string,CrmEntityListItem>();
                Wrapper.IterateMetaEntities(
                    EntityInternalItems.EntityOnly, true, true,
                    delegate(string entityNm, string displayNm)
                    {
                        int typeCd              =   Wrapper.GetObjectTypeCode(entityNm);
                        CrmEntityListItem it    =   new CrmEntityListItem(displayNm, typeCd, entityNm);
                        AllEntities.Add(entityNm,it);
                    }
                    );
            string timestamp                    =   Wrapper.LastTimestamp;
			if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]MetadataCache GetAllEntities END insert in cache Count: {0}, timestamp: {1}.",AllEntities.Count,timestamp),CRMTraceSwitch.Sw.Info);
			// Insert the entity metadata into the cache 15 minutes
            ob                                  =   new object[]{AllEntities,timestamp};
			Settings.Cache.CurrentCache.InsertMinutes(metadataKey,ob, Config.CRMMetadataCacheTime);
            return AllEntities;
        }
    }
}
